package cn.iocoder.yudao.module.trade.order.service.calculator;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.business.basic.convert.BigDecimalConvert;
import cn.iocoder.yudao.module.api.infrastructure.config.dto.MemberConfigRespDTO;
import cn.iocoder.yudao.module.api.promotion.activity.enums.PromotionTypeEnum;
import cn.iocoder.yudao.module.api.trade.order.enums.TradeOrderTypeEnum;
import cn.iocoder.yudao.module.trade.order.bo.TradePriceCalculateReqBO;
import cn.iocoder.yudao.module.trade.order.bo.TradePriceCalculateRespBO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;

/**
 * 使用联盟豆的 {@link TradePriceCalculator} 实现类
 *
 * @author 山野羡民
 */
@Component
@Order(TradePriceCalculator.ORDER_CRYPTOCURRENCY_DEDUCT)
@Slf4j
public class TradeCryptocurrencyDeductPriceCalculator implements TradePriceCalculator {

    @Override
    public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
        // 0.1 判断订单类型是否享受联盟豆抵扣
        if (Arrays.asList(TradeOrderTypeEnum.SECKILL.getType(), TradeOrderTypeEnum.BARGAIN.getType(),
                TradeOrderTypeEnum.COMBINATION.getType(), TradeOrderTypeEnum.POINT.getType(),
                TradeOrderTypeEnum.GROUPON.getType()).contains(result.getType())) {
            log.debug("[calculate][只有非优惠活动订单({})，才处理联盟豆抵扣]", result.getType());
            return;
        }
        // 0.2 校验是否使用联盟豆抵扣
        if (!param.isUseCryptocurrencyDeduction()) {
            log.debug("[calculate][订单未明确使用联盟豆抵扣，联盟豆抵扣不生效]");
            return;
        }
        // 1.1 校验用户联盟豆余额
        if (result.getTotalCryptocurrency() == null || result.getTotalCryptocurrency().doubleValue() <= 0) {
            log.debug("[calculate][用户联盟豆余额为空，联盟豆抵扣不生效]");
            return;
        }
        // 1.2 校验联盟豆抵扣是否开启
        MemberConfigRespDTO config = result.getMemberConfig();
        if (config == null) {
            log.debug("[calculate][未获取到用户中心配置，联盟豆抵扣开关未知，联盟豆抵扣不生效]");
            return;
        }
        if (config.isCryptocurrencyDeductDisable()) {
            log.debug("[calculate][联盟豆抵扣未开启，联盟豆抵扣不生效]");
            return;
        }
        List<TradePriceCalculateRespBO.OrderItem> orderItems = filterList(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSelected);
        // 2.1 计算联盟豆优惠金额
        int sumDeductCount = 0;
        for (TradePriceCalculateRespBO.OrderItem item : orderItems) {
            sumDeductCount += item.getSkuCryptocurrencyDeductCount() * item.getCount();
        }
        log.debug("[calculate][计算联盟豆优惠金额，需要 {} 个联盟豆抵扣", sumDeductCount);
        int sumCryptocurrencyPrice = calculateCryptocurrencyPrice(config, sumDeductCount, result);
        // 2.2 计算分摊的联盟豆、抵扣金额
        List<Integer> dividePrices = TradePriceCalculatorHelper.dividePrice(orderItems, sumCryptocurrencyPrice);
        // 3.1 记录优惠明细
        TradePriceCalculatorHelper.addPromotion(result, orderItems,
                param.getUserId(), "联盟豆抵扣", PromotionTypeEnum.CRYPTOCURRENCY.getValue(),
                StrUtil.format("联盟豆抵扣：省 {} 元", TradePriceCalculatorHelper.formatPrice(sumCryptocurrencyPrice)),
                dividePrices);
        // 3.2 更新 SKU 优惠金额
        for (int i = 0, n = orderItems.size(); i < n; i++) {
            TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i);
            orderItem.setCryptocurrencyPrice(dividePrices.get(i));
            TradePriceCalculatorHelper.recountPayPrice(orderItem);
        }
        TradePriceCalculatorHelper.recountAllPrice(result);
        if (sumDeductCount > 0 && result.getPrice().getPayPrice() < 100) {
            // 联盟豆抵扣后实付款小于100分钱（1元），说明是联盟豆全额抵扣，即联盟豆兑换
            result.setType(TradeOrderTypeEnum.CRYPTOCURRENCY.getType());
        }
        log.debug("[calculate][联盟豆抵扣价格计算完成] {}", result.getPrice());
    }

    private int calculateCryptocurrencyPrice(MemberConfigRespDTO config, int requireCryptocurrency, TradePriceCalculateRespBO result) {
        double deductCryptocurrency = requireCryptocurrency;
        deductCryptocurrency = Math.min(deductCryptocurrency, result.getTotalCryptocurrency().doubleValue());
        log.debug("[calculateCryptocurrencyPrice][每个订单实际使用联盟豆为 {}，1 个联盟豆抵扣 {} 分]", deductCryptocurrency, config.getCryptocurrencyTradeDeductUnitPrice());
        // 联盟豆优惠金额（分）
        int cryptocurrencyPrice = (int) (deductCryptocurrency * config.getCryptocurrencyTradeDeductUnitPrice()); // 确保整数抵扣
        log.debug("[calculateCryptocurrencyPrice][联盟豆 {} 抵扣金额 {}, 原本需支付金额 {}]", deductCryptocurrency, cryptocurrencyPrice, result.getPrice().getPayPrice());
        // 允许 0 元购，即允许联盟豆全额抵扣。用户联盟豆比较多时，联盟豆可以抵扣的金额要大于支付金额，这时需要根据支付金额反推使用多少联盟豆
        if (result.getPrice().getPayPrice() < cryptocurrencyPrice) {
            cryptocurrencyPrice = result.getPrice().getPayPrice();
            // 反推需要扣除的联盟豆
            deductCryptocurrency = NumberUtil.toBigDecimal(cryptocurrencyPrice)
                    .divide(NumberUtil.toBigDecimal(config.getPointTradeDeductUnitPrice()), 0, RoundingMode.HALF_UP)
                    .doubleValue();
        }
        // 记录使用的联盟豆
        result.setDeductCryptocurrency(BigDecimalConvert.INSTANCE.convert(deductCryptocurrency));
        return cryptocurrencyPrice;
    }

}
